# 集装箱装货算法模块
import math

def calculate_loading_plan(container, cargo_list):
    """
    计算集装箱装货方案
    :param container: 集装箱信息字典
    :param cargo_list: 货物列表
    :return: 装货方案列表，包含货物位置、朝向和重量分布信息
    """
    loading_plan = []
    total_weight = 0
    front_weight = 0  # 前轴区域重量
    rear_weight = 0   # 后轴区域重量
    remaining_space = container['length'] * container['width'] * container['height']
    placed_volume = 0
    
    # 初始化装载空间管理
    front_area_length = container['front_length']
    rear_area_length = container['rear_length']
    
    # 存储已放置货物信息，用于碰撞检测
    placed_cargoes_front = []
    placed_cargoes_rear = []
    
    def is_overlapping(new_cargo, existing_cargoes):
            """检查新货物是否与现有货物重叠，添加微小容差处理浮点精度问题"""
            epsilon = 1e-6  # 微小容差，防止浮点精度导致的误判
            for ec in existing_cargoes:
                # 检查边界框是否重叠
                overlap_x = (new_cargo['x'] + epsilon < ec['x'] + ec['length'] and
                             new_cargo['x'] + new_cargo['length'] - epsilon > ec['x'])
                overlap_y = (new_cargo['y'] + epsilon < ec['y'] + ec['width'] and
                             new_cargo['y'] + new_cargo['width'] - epsilon > ec['y'])
                overlap_z = (new_cargo['z'] + epsilon < ec['z'] + ec['height'] and
                             new_cargo['z'] + new_cargo['height'] - epsilon > ec['z'])
                if overlap_x and overlap_y and overlap_z:
                    return True
            return False
    
    def try_place_cargo(cargo, area_length, existing_cargoes, start_x=0):
        """尝试在指定区域放置货物，返回放置位置或None"""
        # 尝试不同朝向 (原始朝向、旋转90度、垂直放置)
        orientations = [
            (cargo['length'], cargo['width'], cargo['height']),  # 原始朝向
            (cargo['width'], cargo['length'], cargo['height']),  # 宽度-长度旋转
            (cargo['length'], cargo['height'], cargo['width']),  # 高度-宽度旋转
        ]
        
        for length, width, height in orientations:
            # 检查基本尺寸是否符合区域要求
            if length > area_length or width > container['width'] or height > container['height']:
                continue
            
            # 尝试在x方向寻找合适位置
            # 先沿y轴排列再沿x轴排列以实现紧密横向排列
            y = 0.0
            while y + width <= container['width']:
                # 尝试0.01单位的精细步进
                current_y = y
                y += 0.01
                x = float(start_x)
                while x + length <= area_length:
                    # 尝试0.01单位的精细步进
                    current_x = x
                    x += 0.01
                    # 尝试在z方向堆叠
                    max_z = 0
                    for ec in existing_cargoes:
                        if (ec['x'] < x + length and ec['x'] + ec['length'] > x and
                            ec['y'] < y + width and ec['y'] + ec['width'] > y):
                            # 该位置已有货物，取其顶部高度
                            if ec['z'] + ec['height'] > max_z:
                                max_z = ec['z'] + ec['height']
                    
                    # 检查是否有足够高度
                    if max_z + height > container['height']:
                        continue
                    
                    # 创建新货物信息
                    new_cargo = {
                        'name': cargo['name'],
                        'x': current_x,
                        'y': current_y,
                        'z': max_z,
                        'orientation': f'{length}x{width}x{height}',
                        'weight': cargo['weight'],
                        'length': length,
                        'width': width,
                        'height': height
                    }
                    
                    # 检查是否与现有货物重叠
                    if not is_overlapping(new_cargo, existing_cargoes):
                        return new_cargo
        return None
    
    # 按体积排序货物，大体积优先放置
    sorted_cargoes = sorted(cargo_list, key=lambda c: c['length']*c['width']*c['height'], reverse=True)
    
    for cargo in sorted_cargoes:
        placed = False
        # 尝试在前轴区域放置
        placed_cargo = try_place_cargo(cargo, front_area_length, placed_cargoes_front)
        if placed_cargo:
            placed_cargo['position'] = 'front'
            loading_plan.append(placed_cargo)
            placed_cargoes_front.append(placed_cargo)
            front_weight += cargo['weight']
            total_weight += cargo['weight']
            placed_volume += placed_cargo['length'] * placed_cargo['width'] * placed_cargo['height']
            placed = True
        
        # 如前区域无法放置，尝试后区域
        if not placed:
            placed_cargo = try_place_cargo(cargo, rear_area_length, placed_cargoes_rear, front_area_length)
            if placed_cargo:
                placed_cargo['position'] = 'rear'
                loading_plan.append(placed_cargo)
                placed_cargoes_rear.append(placed_cargo)
                rear_weight += cargo['weight']
                total_weight += cargo['weight']
                placed_volume += placed_cargo['length'] * placed_cargo['width'] * placed_cargo['height']
        
    # 添加空间利用率信息
    utilization = (placed_volume / remaining_space) * 100 if remaining_space > 0 else 0
    loading_plan.append({'utilization': utilization})
    
    # 检查重量限制
    if total_weight > container['max_weight']:
        print(f"警告: 总重量 {total_weight}kg 超过集装箱最大承重 {container['max_weight']}kg")
    if front_weight > container['front_axle_limit']:
        print(f"警告: 前轴区域重量 {front_weight}kg 超过限制 {container['front_axle_limit']}kg")
    if rear_weight > container['rear_axle_limit']:
        print(f"警告: 后轴区域重量 {rear_weight}kg 超过限制 {container['rear_axle_limit']}kg")
    
    return loading_plan